"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

import sys
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import Permission
from django.db.models import Max, Q

from siriuso.models.postgres import CallableEncoder
from siriuso.utils import default_lingvo, get_enhavo, perms
from universo_bazo.models import UniversoBazaMaks, Realeco
from main.models import Uzanto


# Типы звёздных систем в Универсо, использует абстрактный класс UniversoBazaMaks
class KosmoStelsistemoTipo(UniversoBazaMaks):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор (пользователь, который создал сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # название, многоязычное в JSON формате
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание, многоязычное в JSON формате
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # параллельный мир в котором есть эта сущность, может быть в нескольких
    realeco = models.ManyToManyField(Realeco, verbose_name=_('Realeco'),
                                     db_table='kosmo_stelsistemoj_tipoj_realeco_ligiloj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'kosmo_stelsistemoj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de stelsistemoj')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de stelsistemoj')
        # права
        permissions = (
            ('povas_vidi_kosmo_stelsistemoj_tipoj', _('Povas vidi tipoj de stelsistemoj')),
            ('povas_krei_kosmo_stelsistemoj_tipoj', _('Povas krei tipoj de stelsistemoj')),
            ('povas_forigi_kosmo_stelsistemoj_tipoj', _('Povas forigi tipoj de stelsistemoj')),
            ('povas_sxangxi_kosmo_stelsistemoj_tipoj', _('Povas ŝanĝi tipoj de stelsistemoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nomo этой модели
        return '{}) {}'.format(self.id, get_enhavo(self.nomo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(KosmoStelsistemoTipo, self).save(force_insert=force_insert, force_update=force_update,
                                                       using=using, update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('kosmo',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'kosmo.povas_vidi_kosmo_stelsistemoj_tipoj',
                'kosmo.povas_krei_kosmo_stelsistemoj_tipoj',
                'kosmo.povas_forigi_kosmo_stelsistemoj_tipoj',
                'kosmo.povas_sxangxi_kosmo_stelsistemoj_tipoj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='kosmo', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj_tipoj')
                    or user_obj.has_perm('kosmo.povas_vidi_kosmo_stelsistemoj_tipoj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj_tipoj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Звёздные системы в Универсо, использует абстрактный класс UniversoBazaMaks
class KosmoStelsistemo(UniversoBazaMaks):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # автор (пользователь, который создал сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None,
                               on_delete=models.CASCADE)

    # тип звёздной системы Универсо
    tipo = models.ForeignKey(KosmoStelsistemoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # название, многоязычное в JSON формате
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание, многоязычное в JSON формате
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # параллельный мир в котором есть эта сущность, может быть в нескольких
    realeco = models.ManyToManyField(Realeco, verbose_name=_('Realeco'),
                                     db_table='kosmo_stelsistemoj_realeco_ligiloj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'kosmo_stelsistemoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Stelsistemo')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Stelsistemoj')
        # права
        permissions = (
            ('povas_vidi_kosmo_stelsistemoj', _('Povas vidi stelsistemoj')),
            ('povas_krei_kosmo_stelsistemoj', _('Povas krei stelsistemoj')),
            ('povas_forigi_kosmo_stelsistemoj', _('Povas forigi stelsistemoj')),
            ('povas_sxangxi_kosmo_stelsistemoj', _('Povas ŝanĝi stelsistemoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле nomo этой модели
        return '{}'.format(get_enhavo(self.nomo, empty_values=True)[0])

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(KosmoStelsistemo, self).save(force_insert=force_insert, force_update=force_update,
                                                   using=using, update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('kosmo',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'kosmo.povas_vidi_kosmo_stelsistemoj',
                'kosmo.povas_krei_kosmo_stelsistemoj',
                'kosmo.povas_forigi_kosmo_stelsistemoj',
                'kosmo.povas_sxangxi_kosmo_stelsistemoj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='kosmo', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj')
                    or user_obj.has_perm('kosmo.povas_vidi_kosmo_stelsistemoj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond


# Кубы (ячейки, чанки) звёздных систем в Универсо, использует абстрактный класс UniversoBazaMaks
class KosmoStelsistemoKubo(UniversoBazaMaks):

    # TODO поле ID вводится на время начальной разработки, но позже скорее всего уберём
    # уникальный личный ID
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # звёздная система Универсо
    stelsistemo = models.ForeignKey(KosmoStelsistemo, verbose_name=_('Stelsistemo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # TODO нужно будет решить будем ли указывать связи куба со всех сторон с другими кубами
    # соседняя ячейка со стороны 1
    # najbaro_1 = models.ForeignKey('self', verbose_name=_('Najbara kubo 1'), null=True, blank=True,
    #                               default=None, on_delete=models.CASCADE)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'kosmo_stelsistemoj_kuboj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Kubo de stelsistemo')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Kuboj de stelsistemoj')
        # права
        permissions = (
            ('povas_vidi_kosmo_stelsistemoj_kuboj', _('Povas vidi kuboj de stelsistemoj')),
            ('povas_krei_kosmo_stelsistemoj_kuboj', _('Povas krei kuboj de stelsistemoj')),
            ('povas_forigi_kosmo_stelsistemoj_kuboj', _('Povas forigi kuboj de stelsistemoj')),
            ('povas_sxangxi_kosmo_stelsistemoj_kuboj', _('Povas ŝanĝi kuboj de stelsistemoj')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле id этой модели
        return '{}'.format(self.id)

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(KosmoStelsistemoKubo, self).save(force_insert=force_insert, force_update=force_update,
                                                       using=using, update_fields=update_fields)

    # Права доступа
    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения
            all_perms = set(perms.user_registrita_perms(apps=('kosmo',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'kosmo.povas_vidi_kosmo_stelsistemoj_kuboj',
                'kosmo.povas_krei_kosmo_stelsistemoj_kuboj',
                'kosmo.povas_forigi_kosmo_stelsistemoj_kuboj',
                'kosmo.povas_sxangxi_kosmo_stelsistemoj_kuboj'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='kosmo', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj_kuboj')
                    or user_obj.has_perm('kosmo.povas_vidi_kosmo_stelsistemoj_kuboj')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('kosmo.povas_vidi_kosmo_stelsistemoj_kuboj'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond
